this 指向

# this 指向

this: 指的是调用 当前 方法(函数)的那个对象。

[TOC]

# 一、指向原则

# 1.1 哪个对象调用函数,函数里面的this指向哪个对象。

oBtn.onclick = function() {
    alert(this);	//oBtn
}

oBtn.onclick = fn;	//oBtn
function fn() {
    alert(this);
}

fn();	// window
<div onclick="fn"></div>	// window


let obj = {
    foo: function(){
        console.log(this);
    }
}
obj.foo();	// obj
let obj1 = obj.foo;
obj1();		// window
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21

# 1.2 当函数里面嵌套函数的时候,嵌套里的函数this指向window。

  • 原因不深究,JS特性。
oBtn.onclick = function() {
    alert(this);	//oBtn
    fn()
}
function fn() {
    alert(this);	//window
}
1
2
3
4
5
6
7
  • 解决办法
1. 将this作为参数传进去。
oBtn.onclick = function() {
    alert(this);	//oBtn
    fn(this)
}
function fn(obj) {
    alert(obj);	//oBTn
}
1
2
3
4
5
6
7
  1. 将this保存起来赋给另一个变量。
var _this = null;
oBtn.onclick = function() {
    alert(this);	//oBtn
    _this = this;
    fn();
}
function fn(){
    alert(_this);	// oBtn
}
1
2
3
4
5
6
7
8
9

# 1.3 对于箭头函数,this关键字指向它所在上下文(定义时的位置)的环境。

const shape = {
    radius: 10,
    diameter() {
        return this.radius * 2;
    },
    // this 指向 window
    perimeter: () => 2 * Math.PI * this.radius
};

console.log(shape.diameter());	// 20
console.log(shape.perimeter());	// NaN
1
2
3
4
5
6
7
8
9
10
11
function Timer () {
    this.s1 = 0;
    this.s2 = 0;
    setInterval(() => {
        this.s1++;
        console.log(this, this.s1);		
    }, 2000);
    setInterval(function () {
        this.s2++;
        console.log(this, this.s2);	
    }, 2000)
}
var timer = new Timer();
// Timer{s1: 1, s2: 0} 1
// window NaN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15

# 1.4 立即执行函数的this指向window。

let obj = {};
obj.fn1 = function(){console.log(this)};
obj.fn1();										// obj
obj.fn2 = (function(){console.log(this)})();	// window
1
2
3
4

# 二、改变this指向

# 2.1 bind()

this.x = 9;
var module = {
    x: 81,
    getX: function() { return this.x; }
};
module.getX();	// 81

var getX = moudle.getX;
getX();	// 9

var bindGetX = getX.bind(module);
bindGetX();	// 81
1
2
3
4
5
6
7
8
9
10
11
12

# 三、练一练

  • 第一关
var a = 1;
var obj = {
    a: 1,
    b: {
        c: '2',
        d: function () {
            console.log(this.a);
        }
    }
};
var fn = obj.b;
var fn1 = obj.b.d;
obj.b.d();
fn.d();		
fn1();
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
undefined    // obj.b.d()这个函数this,就是指向b,不会说找不到a,再向上查找
undefined    // fn.d()指向是b,b里面没有a,就是undefined
1    // fn1()指向是window
1
2
3
  • 第二关
let obj={
    fn:function(){
        console.log(this);
        setTimeout(function(){console.log(this)})
    }
};
obj.fn();
// obj
// window,传给 setTimeout 的是普通函数
1
2
3
4
5
6
7
8
9
  • 第三关
var btn = document.getElementById('btn');
btn.attachEvent("onclick", function(){
    console.log(this);
});

// window
// 在使用attachEvent()方法的情况下,事件处理程序会在全局作用域中运行,因此this等于window。
1
2
3
4
5
6
7
  • 第四关
let obj = {
    name: 'jack',
    func() {
        console.log(this.name)
    }
}
let obj2 = {
    name: 'jay'
}
var func = obj.func.bind(obj);
func.call(obj2)	// jack

// this永远指向第一次bind绑定的函数
// 将一个对象强制且永久性绑定到函数的this上,使用call,apply或者其他的绑定方式都无法改变(除了new绑定)
1
2
3
4
5
6
7
8
9
10
11
12
13
14